Skip to content

Conversation

@mpdude
Copy link
Contributor

@mpdude mpdude commented Jun 1, 2023

This change improves scheduling of extra updates in the BasicEntityPersister.

Extra updates can be avoided when

  • the referred-to entity has already been inserted during the current insert batch/transaction and the post-insert (database) ID is already available in the entity
  • we have a self-referencing entity with application-provided ID values (the NONE generator strategy).

As a corollary, with this change applications that provide their own IDs can define self-referencing associations as not NULLable.

One caveat, though: In the absence of entity-level commit ordering (#10547), it is not guaranteed that entities with self-references (at the class level) will be inserted in a suitable order. The order depends on the sequence in which the entities were added with persist().

Fixes #7877, closes #7882.

Co-authored-by: Sylvain Fabre [email protected]

@mpdude mpdude force-pushed the nullable-self-reference-application-provided-id branch from 96ce115 to b0d8fec Compare June 1, 2023 06:42
@mpdude mpdude mentioned this pull request Jun 1, 2023
@mpdude mpdude force-pushed the nullable-self-reference-application-provided-id branch 2 times, most recently from 7870752 to 592fe57 Compare June 2, 2023 06:40
@mpdude
Copy link
Contributor Author

mpdude commented Jun 2, 2023

We need to process the post-insert IDs earlier: Not after executeInserts() has been finished, but rather during the execution. → #10743

@mpdude mpdude force-pushed the nullable-self-reference-application-provided-id branch 2 times, most recently from dc62bb6 to 520a6f4 Compare June 2, 2023 09:29
@mpdude mpdude marked this pull request as draft June 2, 2023 09:39
@mpdude mpdude force-pushed the nullable-self-reference-application-provided-id branch from 520a6f4 to 82a2ed6 Compare June 2, 2023 12:28
@mpdude mpdude changed the base branch from 2.15.x to 2.16.x June 2, 2023 12:28
mpdude added a commit to mpdude/doctrine2 that referenced this pull request Jun 21, 2023
This refactoring does two things:

* We can avoid collecting the post insert IDs in a cumbersome array structure that will be returned by the EntityPersisters and processed by the UoW right after. Instead, use a more expressive API: Make the EntityPersisters tell the UoW about the IDs immediately.
* IDs will be available in inserted entities a tad sooner. That may help to resolve doctrine#10735, where we can use the IDs to skip extra updates.
mpdude added a commit to mpdude/doctrine2 that referenced this pull request Jun 21, 2023
This refactoring does two things:

* We can avoid collecting the post insert IDs in a cumbersome array structure that will be returned by the EntityPersisters and processed by the UoW right after. Instead, use a more expressive API: Make the EntityPersisters tell the UoW about the IDs immediately.
* IDs will be available in inserted entities a tad sooner. That may help to resolve doctrine#10735, where we can use the IDs to skip extra updates.
mpdude added a commit to mpdude/doctrine2 that referenced this pull request Jun 21, 2023
This refactoring does two things:

* We can avoid collecting the post insert IDs in a cumbersome array structure that will be returned by the EntityPersisters and processed by the UoW right after. Instead, use a more expressive API: Make the EntityPersisters tell the UoW about the IDs immediately.
* IDs will be available in inserted entities a tad sooner. That may help to resolve doctrine#10735, where we can use the IDs to skip extra updates.
mpdude added a commit to mpdude/doctrine2 that referenced this pull request Jun 21, 2023
This refactoring does two things:

* We can avoid collecting the post insert IDs in a cumbersome array structure that will be returned by the EntityPersisters and processed by the UoW right after. Instead, use a more expressive API: Make the EntityPersisters tell the UoW about the IDs immediately.
* IDs will be available in inserted entities a tad sooner. That may help to resolve doctrine#10735, where we can use the IDs to skip extra updates.
mpdude added a commit to mpdude/doctrine2 that referenced this pull request Jun 21, 2023
This refactoring does two things:

* We can avoid collecting the post insert IDs in a cumbersome array structure that will be returned by the EntityPersisters and processed by the UoW right after. Instead, use a more expressive API: Make the EntityPersisters tell the UoW about the IDs immediately.
* IDs will be available in inserted entities a tad sooner. That may help to resolve doctrine#10735, where we can use the IDs to skip extra updates.
mpdude added a commit to mpdude/doctrine2 that referenced this pull request Jun 23, 2023
This refactoring does two things:

* We can avoid collecting the post insert IDs in a cumbersome array structure that will be returned by the EntityPersisters and processed by the UoW right after. Instead, use a more expressive API: Make the EntityPersisters tell the UoW about the IDs immediately.
* IDs will be available in inserted entities a tad sooner. That may help to resolve doctrine#10735, where we can use the IDs to skip extra updates.
…hen using application-provided IDs

This change improves scheduling of extra updates in the `BasicEntityPersister`.

Extra updates can be avoided when
* the referred-to entity has already been inserted during the current insert batch/transaction
* we have a self-referencing entity with application-provided ID values (the `NONE` generator strategy).

As a corollary, with this change applications that provide their own IDs can define self-referencing associations as not NULLable.

I am considering this a bugfix since the ORM previously executed additional queries that were not strictly necessary, and that required users to work with NULLable columns where conceptually a non-NULLable column would be valid and more expressive.

One caveat, though:

In the absence of entity-level commit ordering (doctrine#10547), it is not guaranteed that entities with self-references (at the class level) will be inserted in a suitable order. The order depends on the sequence in which the entities were added with `persist()`.

Fixes doctrine#7877, closes doctrine#7882.

Co-authored-by: Sylvain Fabre <[email protected]>
@mpdude mpdude force-pushed the nullable-self-reference-application-provided-id branch from 82a2ed6 to de85359 Compare July 7, 2023 11:41
@mpdude mpdude marked this pull request as ready for review July 7, 2023 11:42
@derrabus derrabus added this to the 2.16.0 milestone Jul 8, 2023
@derrabus derrabus merged commit efc83bc into doctrine:2.16.x Jul 8, 2023
@mpdude mpdude deleted the nullable-self-reference-application-provided-id branch July 8, 2023 14:01
@sylfabre
Copy link
Contributor

Thanks a lot @mpdude 💪

@mpdude
Copy link
Contributor Author

mpdude commented Jul 10, 2023

@sylfabre could you please close #7882 and #7877 when this change here solved the issue?

Thanks!

mpdude added a commit to mpdude/doctrine2 that referenced this pull request Aug 1, 2023
…cation-provided IDs

This excludes such associations from the commit order computation, since the foreign key constraint will be satisfied when inserting the row.

See doctrine#10735 for more details about this edge case.
mvorisek added a commit to mvorisek/orm that referenced this pull request Jul 20, 2025
Fix JoinedSubclassPersister as BasicEntityPersister was already fixed in doctrineGH-10735.

I have extracted this from reworked doctrineGH-8260 which will target v3.x.

The fix can be verified by modifying UnitOfWork to execute `BasicEntityPersister::executeInserts()` for multiple entities at once for the same entity class/persister instance - https://github.com/doctrine/orm/blob/2.20.3/src/UnitOfWork.php#L1186 - then reproducible on `Doctrine\Tests\ORM\Functional\Ticket\GH10531Test::testInserts` test.

As extending/modifying UnitOfWork in tests in not easily possible, I submit this fix for v2.x without a test.
mvorisek added a commit to mvorisek/orm that referenced this pull request Aug 1, 2025
Fix JoinedSubclassPersister as BasicEntityPersister was already fixed in doctrineGH-10735.

The fix can be verified by modifying UnitOfWork to execute `BasicEntityPersister::executeInserts()` for multiple entities at once for the same entity class/persister instance - https://github.com/doctrine/orm/blob/2.20.3/src/UnitOfWork.php#L1186 - then reproducible on `Doctrine\Tests\ORM\Functional\Ticket\GH10531Test::testInserts` test.

As extending/modifying UnitOfWork in tests in not easily possible, I submit this fix for v2.x without a test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extra update for self-referencing Many-To-One with NONE generator strategy during persist

3 participants